package com.didi.gulimall.seckill.job;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.didi.gulimall.api.CouponApiService;
import com.didi.gulimall.api.ProductApiService;
import com.didi.gulimall.common.constant.SecKillConstant;
import com.didi.gulimall.common.exception.DuplicateFieldsException;
import com.didi.gulimall.common.exception.GulimallExceptionControllerAdvice;
import com.didi.gulimall.common.to.SkuInfoTO;
import com.didi.gulimall.common.utils.DateUtil;
import com.didi.gulimall.common.utils.R;
import com.didi.gulimall.seckill.vo.SeckillSesssionsWithSkus;
import com.didi.gulimall.seckill.vo.SeckillSkuVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author 10626
 * @Create 2021/6/15 17:56
 */
@EnableScheduling
@Configuration
@Slf4j
public class SecKillJob {
    @Autowired
    private CouponApiService couponApiService;

    @Autowired
    private ProductApiService productApiService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 上架秒杀前三天
     */
//    @Scheduled(cron = "* * * * * ?")
    public void SeckillShelves() {
        R r = couponApiService.getInfoNearlyThreeDays();
        if (r.getCode() == 0) {
            List<SeckillSesssionsWithSkus> data = r.getData(new TypeReference<List<SeckillSesssionsWithSkus>>() {
            });
            for (SeckillSesssionsWithSkus session : data) {
                long startTime = session.getStartTime().getTime();
                long endTime = session.getEndTime().getTime();
                String key = SecKillConstant.SESSIONS_CACHE_PREFIX + startTime + "_" + endTime;
                log.info("执行上架任务key:{}", key);
                BoundHashOperations<String, String, String> boundHashOps = redisTemplate.boundHashOps(key);
                long time = DateUtil.getTime(session.getEndTime());
                List<SeckillSkuVo> relationSkus = session.getRelationSkus();
                if (CollectionUtils.isNotEmpty(relationSkus)) {
                    for (SeckillSkuVo skus : relationSkus) {
                        if (!boundHashOps.hasKey(skus.getSkuId().toString())) {
                            String token = UUID.randomUUID().toString().replace("-", "");
                            R info = productApiService.info(skus.getSkuId());
                            if (info.getCode() != 0) {
                                throw new DuplicateFieldsException(info.getMsg());
                            }
                            SkuInfoTO skuInfo = info.getData("skuInfo", new TypeReference<SkuInfoTO>() {
                            });
                            // TODO  销售属性选项   积分优惠
                            BeanUtils.copyProperties(session, skuInfo);
                            skuInfo.setStartTime(startTime);
                            skuInfo.setEndTime(endTime);
                            BeanUtils.copyProperties(skus, skuInfo);
                            skuInfo.setRandomCode(token);
                            boundHashOps.put(skus.getSkuId().toString(), JSON.toJSONString(skuInfo));
                            RSemaphore semaphore = redissonClient.getSemaphore(SecKillConstant.SKU_STOCK_SEMAPHORE + token);
                            //商品可以秒杀的数量作为信号量
                            boolean b = semaphore.trySetPermits(skus.getSeckillCount());
                            if (!b){
                                throw new RuntimeException("aaa");
                            }
                            log.info("商品可以秒杀的数量作为信号量：{}", b);
                            semaphore.expire(time, TimeUnit.MILLISECONDS);
                            //TODO 设置过期时间。
                        }
                    }
                    if (!redisTemplate.hasKey(key)) {
                        Boolean expire = redisTemplate.expire(key, time, TimeUnit.MILLISECONDS);
                        log.info("设置过期时间：{}", expire);
                    }
                }
            }
        }
    }
}
